﻿//-----------------------------------------------------------------------------
//<filedescription file="ArrayBuilder.Utilities.cs" company="Microsoft">
//  <copyright>
//     Copyright © Microsoft Corporation.  All rights reserved.
//     ***  DESIGNATED SAMPLE CODE (per the included software license terms) ***
//      THIS CODE SAMPLE IS MADE AVAILABLE TO YOU WITHOUT WARRANTY OF ANY KIND
//      AND CONFERS NO RIGHTS ON YOU WHATSOEVER EXCEPT THE RIGHT TO REVIEW IT
//      SOLELY AS A REFERENCE.  THE ENTIRE RISK OF USE OR RESULTS FROM USE OF
//      THIS CODE SAMPLE REMAINS WITH YOU.
//  </copyright>
//  <purpose>
//     General utility methods specific to the ArrayBuilder framework.
//  </purpose>
//  <notes>
//  </notes>
//</filedescription>
//-----------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;
using Microsoft.ConfigurationManagement.IntegrationDevelopmentKit;
using Microsoft.ConfigurationManagement.OemDeployment;
using Microsoft.Win32;


namespace Microsoft.ConfigurationManagement.OemDeployment.ArrayBuilder
{
    /// <summary>
    /// 
    /// </summary>
    internal static partial class Utilities
    {

        #region Enums

        /// <summary>
        /// 
        /// </summary>
        internal enum NodeType
        {
            /// <summary>
            /// 
            /// </summary>
            None,
            /// <summary>
            /// 
            /// </summary>
            Controller,
            /// <summary>
            /// 
            /// </summary>
            Variable,
            /// <summary>
            /// 
            /// </summary>
            Array,
            /// <summary>
            /// 
            /// </summary>
            JbodArray,
            /// <summary>
            /// 
            /// </summary>
            LogicalDrives,
            /// <summary>
            /// 
            /// </summary>
            LogicalDrive,
            /// <summary>
            /// 
            /// </summary>
            PhysicalDisks,
            /// <summary>
            /// 
            /// </summary>
            Disk,
            /// <summary>
            /// 
            /// </summary>
            JbodDisk,
            /// <summary>
            /// 
            /// </summary>
            HotSpare,
            /// <summary>
            /// 
            /// </summary>
            AllRemainingDisks,
            /// <summary>
            /// 
            /// </summary>
            GlobalHotSpares,
            /// <summary>
            /// 
            /// </summary>
            GlobalHotSpare,
            /// <summary>
            /// 
            /// </summary>
            Self,
            /// <summary>
            /// 
            /// </summary>
            Adjacent,
            /// <summary>
            /// 
            /// </summary>
            Parent
        }

        #endregion

        #region Properties

        
        #endregion


        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="indent"></param>
        /// <returns></returns>
        internal static string PrintObjectProperties(XmlNode node, string indent)
        {
            if (node == null)
            {
                return null;
            }
            if (indent == null)
            {
                indent = " ";
            }
            string props = "";
            //props += indent + "\n==============================================";
            //props += indent + "\nXmlNode Name:  \t" + node.Name;
            //props += indent + "\n   Value:      \t" + node.Value;
            //props += indent + "\n   Local Name: \t" + node.LocalName;
            //props += indent + "\n   Node type:  \t" + node.NodeType;
            //props += indent + "\n   Owner Doc:  \t" + node.OwnerDocument.Name;
            //props += indent + "\n   Base URI:   \t" + node.BaseURI; 
            //props += indent + "\n   Parent node:\t" + node.ParentNode.Name;
            //props += indent + "\n   NextSibling:\t" + node.NextSibling.Name;
            //props += indent + "\n   PreviousSibling: " + node.PreviousSibling.Name;

            //if (node.Attributes.Count > 0)
            //{
            //    props += indent + "\n   Attributes:";
            //    for (int i = 0; i < node.Attributes.Count; i++)
            //    {
            //        props += "\n" + indent + "     " + node.Attributes[i].Name + ":    \t" + node.Attributes[i].Value;
            //    }
            //}
            //if (node.HasChildNodes)
            //{
            //    for (int i = 0; i < node.ChildNodes.Count; i++ )
            //    {
            //        props = PrintObjectProperties(node.ChildNodes[i], indent + "\t");
            //    }
            //}
            return props;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static int GetXmlNodeIndex(XmlNode node)
        {
            if (node == null)
            {
                throw new System.ArgumentException("node", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
            }
            if (node.ParentNode == null)
            {
                throw new System.ArgumentException("node", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
            }
            XmlNodeList nodes = node.ParentNode.ChildNodes;
            
            for (int i = 0; i < nodes.Count; i++)
            {
                if (nodes[i].Equals(node))
                {
                    //MessageBox.Show(string.Format("GetXmlNodeIndex: returning a value of {0}\n\nNode:{1}", i-1, node.OuterXml));
                    return i;
                }
            }
            //if the node wasn't found (should not happen!)
            throw new System.ArgumentException("node", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
        }



        //===================[ Datagrid ]====================

        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataGrid"></param>
        /// <param name="oemOptionsNode"></param>
        /// <param name="selectedOptions"></param>
        /// <returns></returns>
        internal static DataGridView FillOptionsDataGrid(DataGridView dataGrid, XmlNode oemOptionsNode, XmlNode selectedOptions)
        {
            if (dataGrid == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "dataGrid");
            }
            if (oemOptionsNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "oemOptionsNode");
            }

            //MessageBox.Show("query: " + query);

            //XmlNode optionsNode = IntegrationKitUtilities.GetXmlNode(configXml,".//" + query);
            if (oemOptionsNode == null)
            {
                //no options found in the general config xml. Nothing to set.
                return null;
            }
            dataGrid.Enabled = true;
            dataGrid.Visible = true;

            DataGridViewTextBoxCell nameCell = new DataGridViewTextBoxCell();
            DataGridViewTextBoxCell descriptionCell = new DataGridViewTextBoxCell();
            DataGridViewComboBoxCell valuesCell = new DataGridViewComboBoxCell();

            for (int c = 0; c < oemOptionsNode.ChildNodes.Count; c++)
            {

                nameCell.Value = IntegrationKitUtilities.GetXmlAttribute(oemOptionsNode.ChildNodes[c], "Name");
                descriptionCell.Value = IntegrationKitUtilities.GetXmlAttribute(oemOptionsNode.ChildNodes[c], "Description");
                //MessageBox.Show("set the first two cells");

                valuesCell.Items.Add(Properties.Resources.AdditionalOptions_NotUsed);

                XmlNodeList optionValuesNodes = IntegrationKitUtilities.GetXmlNodeList(oemOptionsNode.ChildNodes[c], "/OptionValue");
                if (optionValuesNodes != null)
                {
                    for (int i = 0; i < optionValuesNodes.Count; i++)
                    {
                        MessageBox.Show("Adding an item to the combobox " + IntegrationKitUtilities.GetXmlAttribute(optionValuesNodes[i], "Name"));
                        valuesCell.Items.Add(IntegrationKitUtilities.GetXmlAttribute(optionValuesNodes[i], "Name"));
                        //MessageBox.Show("valuesCell count: " + valuesCell.Items.Count);
                    }
                }
                //valuesCell.Value = Properties.Resources.AdditionalOptions_NotUsed;

                XmlNode defaultOption = IntegrationKitUtilities.GetXmlNode(oemOptionsNode.ChildNodes[c], "//DefaultOption");
                if (defaultOption != null)
                {
                    string defaultOptionValue = IntegrationKitUtilities.GetXmlAttribute(defaultOption, "Name");
                    if (string.IsNullOrEmpty(defaultOptionValue) == false)
                    {
                        if (valuesCell.Items.Contains(defaultOptionValue))
                        {
                            //valuesCell.Value = defaultOptionValue;
                        }
                    }
                }

                if (selectedOptions != null)
                {
                    XmlNode thisOption = IntegrationKitUtilities.GetXmlNode(selectedOptions, "//Option/[@Name='" + nameCell.Value + "']");
                    if (thisOption != null)
                    {
                        string thisValue = IntegrationKitUtilities.GetXmlAttribute(thisOption, "Value");
                        if (string.IsNullOrEmpty(thisValue) == false)
                        {
                            valuesCell.Value = thisValue;
                        }
                    }
                }

                DataGridViewRow newRow = new DataGridViewRow();
                newRow.Cells.Add(nameCell);
                newRow.Cells.Add(valuesCell);
                newRow.Cells.Add(descriptionCell);
                dataGrid.Rows.Add(newRow);

            }

            return dataGrid;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataGrid"></param>
        /// <param name="elementName"></param>
        /// <returns></returns>
        internal static XmlNode GetOptionsDataGridValues(DataGridView dataGrid, string elementName)
        {
            if (dataGrid == null)
            {
                throw new System.ArgumentException("dataGrid", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(elementName))
            {
                throw new System.ArgumentException("elementName", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
            }
            DataGridViewRowCollection rows = dataGrid.Rows;
            if ((rows != null) && (rows.Count > 0))
            {
                //MessageBox.Show("Found " + rows.Count + " rows in the datagrid");

                XmlDocument xmlContent = new XmlDocument();
                XmlNode optionsNode = null;

                XmlElement optionsTopElement = xmlContent.CreateElement(elementName);
                for (int c = 0; c < rows.Count; c++)
                {
                    XmlElement optionElement = xmlContent.CreateElement("Option");
                    if (rows[c].Cells[0].Value != null)
                    {
                        optionElement.SetAttribute("Name", rows[c].Cells[0].Value.ToString());

                        if ((rows[c].Cells[1].Value != null) &&
                            (string.Compare(rows[c].Cells[1].Value.ToString(), Properties.Resources.AdditionalOptions_NotUsed,
                            StringComparison.OrdinalIgnoreCase) != 0))
                        {
                            optionElement.SetAttribute("Value", rows[c].Cells[1].Value.ToString());
                            optionsTopElement.AppendChild(optionElement);

                        }
                    }
                }
                optionsNode = optionsTopElement;

                //MessageBox.Show("options node being returned: " + optionsNode.OuterXml);

                if ((optionsNode != null) && (optionsNode.HasChildNodes))
                {
                    return optionsNode;
                }
                else
                {
                    //MessageBox.Show("options node was null"); 
                    return null;
                }
            }
            else
            {
                throw new System.ArgumentException("dataGrid.Rows", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
            }
        }



        //===================[ User Notification ]====================


        /// <summary>
        ///     
        /// </summary>
        /// <param name="message" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="caption" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="method" type="System.Reflection.MethodBase">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        internal static void ShowErrorMessage(string message, string caption, MethodBase method)
        {
            string infoText = null;
            if (method != null)
            {
                infoText += "\n Method name: " + method.Name;
                ParameterInfo[] myParams = MethodBase.GetCurrentMethod().GetParameters();
                if (myParams != null)
                {
                    infoText += "\n Parameters: ";
                    foreach (ParameterInfo myParam in myParams)
                    {
                        infoText += "\n  Name: '" + myParam.Name + "'  \tType:   \t" + myParam.ParameterType.ToString();
                    }
                }
                message += infoText;
            }
            if (string.IsNullOrEmpty(caption))
            {
                caption = string.Empty;
            }
            MessageBox.Show(
                message,
                caption,
                MessageBoxButtons.OK,
                MessageBoxIcon.Error,
                MessageBoxDefaultButton.Button1,
                MessageBoxOptions.ServiceNotification);
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="message" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="caption" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A System.Windows.Forms.DialogResult value...
        /// </returns>
        internal static DialogResult ShowNotificationMessage(string message, string caption)
        {
            if (string.IsNullOrEmpty(caption))
            {
                caption = string.Empty;
            }

            return MessageBox.Show(
                message,
                caption,
                MessageBoxButtons.OK,
                MessageBoxIcon.Information,
                MessageBoxDefaultButton.Button1,
                MessageBoxOptions.DefaultDesktopOnly);
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="message" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="caption" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A System.Windows.Forms.DialogResult value...
        /// </returns>
        internal static DialogResult GetUserResponseYesNo(string message, string caption)
        {
            if (string.IsNullOrEmpty(caption))
            {
                caption = Properties.Resources.Text_Warning;
            }

            return MessageBox.Show(
                message,
                caption,
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button2,
                MessageBoxOptions.DefaultDesktopOnly);
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="message" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="caption" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A System.Windows.Forms.DialogResult value...
        /// </returns>
        internal static DialogResult GetUserResponseYesNoCancel(string message, string caption)
        {
            if (string.IsNullOrEmpty(caption))
            {
                caption = Properties.Resources.Text_Warning;
            }

            return MessageBox.Show(
                message,
                caption,
                MessageBoxButtons.YesNoCancel,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button3,
                MessageBoxOptions.DefaultDesktopOnly);
        }


 

        //===================[ Treeview / XML Nodes ]====================

        /// <summary>
        /// Returns a user-specified ancestor or sibling node of the given node.
        /// </summary>
        /// <param name="selectedNode">An XmlNode representing the current node</param>
        /// <param name="nodeToGet">The type of node to retrienve</param>
        /// <returns></returns>
        internal static XmlNode GetSpecificXmlNode(XmlNode selectedNode, NodeType nodeToGet)
        {
            ArgumentNotNull(selectedNode, "selectedNode");

            if (nodeToGet == NodeType.None)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "nodeToGet");
            }

            XmlNode nodeFound = null;
         
            switch (nodeToGet)
            {
                case NodeType.Self:
                    nodeFound = selectedNode;
                    break;

                case NodeType.Disk:
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::Disk");
                    break;

                case NodeType.Array:
                    //goes up to the first array parent
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::Array");
                    break;

                case NodeType.JbodArray:
                    //this query goes up to the first variable condition node and then back down to the jbod array node
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::VariableCondition//descendant::Array[@RaidLevel='None']");
                    break;

                case NodeType.GlobalHotSpares:
                    //this query goes up to the first variable condition node and then back down to the GHS node
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::VariableCondition//descendant::GlobalHotSpares");
                    break;

                case NodeType.LogicalDrive:
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::LogicalDrive");
                    break;

                case NodeType.Variable:
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::VariableCondition");
                    break;

                case NodeType.Controller:
                    nodeFound = IntegrationKitUtilities.GetXmlNode(selectedNode, ".//ancestor-or-self::Controller");
                    break;

                case NodeType.Parent:
                    if (selectedNode.ParentNode != null)
                    {
                        nodeFound = selectedNode.ParentNode;
                    }
                    break;

                case NodeType.Adjacent:
                    if (selectedNode.PreviousSibling != null)
                    {
                        nodeFound = selectedNode.PreviousSibling;
                    }
                    else if (selectedNode.NextSibling != null)
                    {
                        nodeFound = selectedNode.NextSibling;
                    }
                    else
                    {
                        nodeFound = selectedNode.ParentNode;
                    }
                    break;

                default:
                    nodeFound = null;
                    break;
            }
            return nodeFound;
        }
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="xmlToTree"></param>
        /// <param name="nodeToGet"></param>
        /// <returns></returns>
        internal static TreeNode GetSpecificTreeNodeFromXml(XmlNode node, Dictionary<XmlNode, TreeNode> xmlToTree, NodeType nodeToGet)
        {
            if (node == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }
            if (node.ParentNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node.ParentNode");
            }

            NodeType currentNodeType = GetNodeType(node);
            TreeNode selfNode = null;
            TreeNode tNode = null;
            if (xmlToTree.TryGetValue(node, out selfNode) == false)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "selfNode");
            }
            XmlNode ancestorNode = GetSpecificXmlNode(node, nodeToGet) ;
            ArgumentNotNull(ancestorNode, "ancestorNode");

            if (xmlToTree.TryGetValue(ancestorNode, out tNode) == true)
            {
                return tNode;
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="nodeToGet"></param>
        /// <returns></returns>
        internal static TreeNode GetSpecificTreeNode(TreeNode treeNode, NodeType nodeToGet)
        {
            if (treeNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "treeNode");
            }

            if (nodeToGet == NodeType.None)
            {
                return treeNode;
            }

            NodeType nodeType = (NodeType)treeNode.Tag;

            TreeNode diskNode = null;
            TreeNode physicalDisksNode = null;
            TreeNode logicalDriveNode = null;
            TreeNode logicalDrivesNode = null;
            TreeNode arrayNode = null;
            TreeNode jbodArrayNode = null;
            TreeNode globalHotSparesNode = null;
            TreeNode variableNode = null;
            TreeNode controllerNode = null;

            if (nodeType == NodeType.Controller)
            {
                controllerNode = treeNode;
            }
            else if (nodeType == NodeType.Variable)
            {
                ArgumentNotNull(treeNode.Parent, "treeNode.Parent");
                controllerNode = treeNode.Parent;
                variableNode = treeNode;
            }
            else if (nodeType == NodeType.Array)
            {
                ArgumentNotNull(treeNode.Parent.Parent, "treeNode.Parent.Parent");
                controllerNode = treeNode.Parent.Parent;
                variableNode = treeNode.Parent;
                arrayNode = treeNode;
            }
            else if (nodeType == NodeType.JbodArray)
            {
                ArgumentNotNull(treeNode.Parent.Parent, "treeNode.Parent.Parent");
                controllerNode = treeNode.Parent.Parent;
                variableNode = treeNode.Parent;
                jbodArrayNode = treeNode;
            }
            else if (nodeType == NodeType.LogicalDrives)
            {
                ArgumentNotNull(treeNode.Parent.Parent.Parent, "treeNode.Parent.Parent.Parent");
                controllerNode = treeNode.Parent.Parent.Parent;
                variableNode = treeNode.Parent.Parent;
                arrayNode = treeNode.Parent;
                logicalDrivesNode = treeNode;
            }
            else if (nodeType == NodeType.LogicalDrive)
            {
                ArgumentNotNull(treeNode.Parent.Parent.Parent.Parent, "treeNode.Parent.Parent.Parent.Parent");
                controllerNode = treeNode.Parent.Parent.Parent.Parent;
                variableNode = treeNode.Parent.Parent.Parent;
                arrayNode = treeNode.Parent.Parent;
                logicalDrivesNode = treeNode.Parent;
                logicalDriveNode = treeNode;
            }
            else if (nodeType == NodeType.PhysicalDisks)
            {
                ArgumentNotNull(treeNode.Parent.Parent.Parent, "treeNode.Parent.Parent.Parent");
                controllerNode = treeNode.Parent.Parent.Parent;
                variableNode = treeNode.Parent.Parent;
                arrayNode = treeNode.Parent;
                physicalDisksNode = treeNode;
            }
            else if ((nodeType == NodeType.AllRemainingDisks) ||
                (nodeType == NodeType.Disk) ||
                (nodeType == NodeType.HotSpare) ||
                (nodeType == NodeType.JbodDisk))
            {
                ArgumentNotNull(treeNode.Parent.Parent.Parent.Parent, "treeNode.Parent.Parent.Parent.Parent");
                controllerNode = treeNode.Parent.Parent.Parent.Parent;
                variableNode = treeNode.Parent.Parent.Parent;
                physicalDisksNode = treeNode.Parent;
                diskNode = treeNode;

                if (nodeType == NodeType.JbodDisk)
                {
                    jbodArrayNode = treeNode.Parent.Parent;
                }
                else
                {
                    arrayNode = treeNode.Parent.Parent;
                }
            }
            else if (nodeType == NodeType.GlobalHotSpares)
            {
                ArgumentNotNull(treeNode.Parent.Parent, "treeNode.Parent.Parent");
                controllerNode = treeNode.Parent.Parent;
                variableNode = treeNode.Parent;
                globalHotSparesNode = treeNode;
            }
            else if (nodeType == NodeType.GlobalHotSpare)
            {
                ArgumentNotNull(treeNode.Parent.Parent.Parent, "treeNode.Parent.Parent.Parent");
                controllerNode = treeNode.Parent.Parent.Parent;
                variableNode = treeNode.Parent.Parent;
                globalHotSparesNode = treeNode.Parent;
                diskNode = treeNode;
            }
            else
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "treeNode");
            }
            

            switch (nodeToGet)
            {
                case NodeType.Self:
                    return treeNode;

                case NodeType.Disk:
                    return diskNode;

                case NodeType.Array:
                    return arrayNode;

                case NodeType.JbodArray:
                    return jbodArrayNode;

                case NodeType.PhysicalDisks:
                    return physicalDisksNode;

                case NodeType.LogicalDrive:
                    return logicalDriveNode;

                case NodeType.LogicalDrives:
                    return logicalDrivesNode;

                case NodeType.GlobalHotSpares:
                    return globalHotSparesNode;

                case NodeType.Variable:
                    return variableNode;

                case NodeType.Controller:
                    return controllerNode;

                case NodeType.Parent:
                    if (treeNode.Parent == null)
                    {
                        return null;
                    }
                    return treeNode.Parent;

                case NodeType.Adjacent:
                    if (treeNode.PrevNode != null)
                    {
                        return treeNode.PrevNode;
                    }
                    else if (treeNode.NextNode != null)
                    {
                        return treeNode.NextNode;
                    }
                    return treeNode.Parent;

                case NodeType.AllRemainingDisks:
                    if (nodeType == NodeType.AllRemainingDisks)
                    {
                        return treeNode;
                    }
                    return null;

                default:
                    return null;
                    //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "nodeToGet");
            }

            
        }

        /// <summary>
        /// Returns an XmlNode of a sibling of the specified node. Previous siblings are tried first, and if none exist, next sibling is returned. If no siblings exist, null is returned.
        /// </summary>
        /// <param name="node">An XmlNode specifing the node for which a sibling will be returned.</param>
        /// <returns>An XmlNode object of the sibling</returns>
        internal static XmlNode GetSibling(XmlNode node)
        {
            if (node == null)
            {
                return null;
            }
            if (node.PreviousSibling != null)
            {
                return node.PreviousSibling;
            }
            else if (node.NextSibling != null)
            {
                return node.NextSibling;
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="treeToXml"></param>
        /// <param name="treeNode"></param>
        /// <param name="nodeToGet"></param>
        /// <returns></returns>
        internal static XmlNode GetXmlNodeFromTree(Dictionary<TreeNode, XmlNode> treeToXml, TreeNode treeNode, NodeType nodeToGet)
        {
            ArgumentNotNull(treeNode, "treeNode");
            ArgumentNotNull(treeToXml, "treeToXml");

            if (nodeToGet == NodeType.None)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "nodeToGet");
            }

            XmlNode selfNode = null;
            
            if (treeToXml.TryGetValue(treeNode, out selfNode) == false)
            {
                return null;
            }

            return GetSpecificXmlNode(selfNode, nodeToGet);
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="method"></param>
        internal static void ShowExceptionMessage(Exception ex, MethodBase method)
        {
            string message = null;
            if (ex == null)
            {
                return;
            }
            else
            {
                message =
                "\n\nex object type:\t" + ex.GetType() +
                "\n\nMessage:       \t" + ex.Message;

                //switch (ex.GetType())
                //{
                //    case ArgumentException:

                //        break;

                //    case XmlException:

                //        break;

                //    case XPathException:

                //        break;

                //    case XmlSyntaxException:

                //        break;

                //    case ArgumentNullException:

                //        break;

                //    case ArgumentOutOfRangeException:

                //        break;

                //    default:
                //        break;
                //}



                message +=
                "\n\nStackTrace:    \t" + ex.StackTrace +
                    //"\n\nInnerException:\t" + ex.InnerException +
                "\n\nData:          \t" + ex.Data +
                "\n\nSource:        \t" + ex.Source +
                    //"\n\nHelpLink:      \t" + ex.HelpLink +
                "\n\nTargetSite:    \t" + ex.TargetSite +
                "\n\nBaseException: \t" + ex.GetBaseException();
            }

            if (method != null)
            {
                message += "\n\n Method name: " + method.Name;
                ParameterInfo[] myParams = MethodBase.GetCurrentMethod().GetParameters();
                if (myParams != null)
                {
                    message += "\n Parameters: ";
                    foreach (ParameterInfo myParam in myParams)
                    {
                        message += "\n  Name: '" + myParam.Name + "'  \tType:   \t" + myParam.ParameterType.ToString();
                    }
                }
            }

            MessageBox.Show(
                message,
                string.Empty,
                MessageBoxButtons.OK,
                MessageBoxIcon.Error,
                MessageBoxDefaultButton.Button1,
                MessageBoxOptions.ServiceNotification);

        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="controllerNode"></param>
        /// <returns></returns>
        internal static string SetControllerNodeTitle(XmlNode controllerNode)
        {
            if (controllerNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "controllerNode");
            }

            string contId = IntegrationKitUtilities.GetXmlAttribute(controllerNode, "Name");
            string nodeTitle = null;

            if (contId != null)
            {
                // controller naming:
                //  - if embedded controller: "Embedded controller" 
                //  - if controller in slot:  "Controller in Slot X"
                //  - if "any"                "Any controller with [exactly | at least] X disks
                //  - if "all"                "All remaining controllers"

                string slotNumber = IntegrationKitUtilities.GetXmlAttribute(controllerNode, "SlotNumber");
                string controllerMatch = IntegrationKitUtilities.GetXmlAttribute(controllerNode, "ControllerMatch");

                if (string.IsNullOrEmpty(slotNumber) == false)
                {
                    if (string.Compare(slotNumber,CONTROLLER_MATCH_EMBEDDED, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        nodeTitle = Properties.Resources.ArrayBuilder_Text_EmbeddedController;
                    }
                    else
                    {
                        nodeTitle = Properties.Resources.ArrayBuilder_Text_ControllerInSlot + " " + slotNumber;
                    }
                }
                else if (string.IsNullOrEmpty(controllerMatch) == false)
                {
                    if (string.Compare(controllerMatch, CONTROLLER_MATCH_ANY, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        string numDrives = IntegrationKitUtilities.GetXmlAttribute(controllerNode, "NumberOfDisks");
                        string diskMatch = IntegrationKitUtilities.GetXmlAttribute(controllerNode, "DiskMatch");
                        if (string.Compare(diskMatch, DRIVE_MATCH_TYPE_EQUAL, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            nodeTitle = Properties.Resources.ArrayBuilder_Text_AnyController + " " + Properties.Resources.ArrayBuilder_Text_EqDisks + numDrives + " " + Properties.Resources.ArrayBuilder_Text_Disks.ToLower(CultureInfo.CurrentCulture);
                        }
                        else
                        {
                            nodeTitle = Properties.Resources.ArrayBuilder_Text_AnyController + " " + Properties.Resources.ArrayBuilder_Text_EqOrGreaterDisks + numDrives + " " + Properties.Resources.ArrayBuilder_Text_Disks.ToLower(CultureInfo.CurrentCulture);
                        }
                    }
                    else
                    {
                        nodeTitle = Properties.Resources.ArrayBuilder_Text_AllRemainingControllers;
                    }
                }
                nodeTitle = "[" + contId + "] " + nodeTitle;
            }

            return nodeTitle;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xmlNode"></param>
        /// <returns></returns>
        internal static string SetVariableNodeTitle(XmlNode xmlNode)
        {
            if (xmlNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "xmlNode");
            }
            string variableName = IntegrationKitUtilities.GetXmlAttribute(xmlNode, "VariableName");
            string nodeTitle = string.Empty;
            if (string.IsNullOrEmpty(variableName) == true)
            {
                nodeTitle = Properties.Resources.ArrayBuilder_Text_WhereVariableNotSet;
            }
            else
            {
                string variableValue = IntegrationKitUtilities.GetXmlAttribute(xmlNode, "VariableValue");
                string comparisonOperator = IntegrationKitUtilities.GetXmlAttribute(xmlNode, "ComparisonOperator");
                //convert the comparison operator XML string to a display string.
                string displayString = IntegrationKitUtilities.GetLocalizedOperator(comparisonOperator);

                if (string.Compare(comparisonOperator, "IsNull", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    nodeTitle = Properties.Resources.ArrayBuilder_Text_WhereVariable + " '" + variableName + "' " + displayString ;
                }
                else
                {
                    nodeTitle = Properties.Resources.ArrayBuilder_Text_WhereVariable + " '" + variableName + "' " + displayString + " '" + variableValue + "'";
                }
            }
            return nodeTitle;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayXmlNode"></param>
        /// <returns></returns>
        internal static string SetArrayNodeTitle(XmlNode arrayXmlNode)
        {
            if (arrayXmlNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayXmlNode");
            }

            string arrayName = IntegrationKitUtilities.GetXmlAttribute(arrayXmlNode, "Name");
            if (string.IsNullOrEmpty(arrayName))
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayName");
            }
            string arrayRaid = IntegrationKitUtilities.GetXmlAttribute(arrayXmlNode, "RaidLevel");
            if (string.IsNullOrEmpty(arrayRaid))
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayRaid");
            }
            string nodeTitle = Properties.Resources.ArrayBuilder_Text_Array + " " + arrayName + " - ";

            switch (arrayRaid)
            {
                case "0":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid0;
                    break;

                case "1":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid1;
                    break;

                case "5":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid5;
                    break;

                case "6":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid6;
                    break;

                case "10":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid10;
                    break;

                case "50":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid50;
                    break;

                case "60":
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_Raid60;
                    break;

                case ARRAY_DYNAMIC:
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_RaidDynamic;
                    break;

                case ARRAY_NO_RAID:
                    nodeTitle = Properties.Resources.ArrayBuilder_Text_RaidNone;
                    break;

                default:
                    nodeTitle += Properties.Resources.ArrayBuilder_Text_RaidUnknown;
                    break;
            }
            return nodeTitle;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logicalDriveNode"></param>
        /// <returns></returns>
        internal static string SetLogicalDriveNodeTitle(XmlNode logicalDriveNode)
        {
            if (logicalDriveNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "logicalDriveNode");
            }
            if (logicalDriveNode.ParentNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "logicalDriveNode");
            }

            XmlNodeList logicalDriveNodes = IntegrationKitUtilities.GetXmlNodeList(logicalDriveNode.ParentNode, XPATH_LOGICAL_DRIVE_NODELIST);
            if ((logicalDriveNodes == null) || (logicalDriveNodes.Count == 0))
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "logicalDriveNode.Parent");
            }
            string nodeTitle = string.Empty;
            string logicalDriveNumber = IntegrationKitUtilities.GetXmlAttribute(logicalDriveNode, "Number");
            string logicalDriveSize = IntegrationKitUtilities.GetXmlAttribute(logicalDriveNode, "Size");
            string logicalDriveType = IntegrationKitUtilities.GetXmlAttribute(logicalDriveNode, "Type");
            if (string.IsNullOrEmpty(logicalDriveSize) == false)
            {
                if (string.Compare(logicalDriveSize, MAXIMUM_SIZE, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    nodeTitle = string.Format(Properties.Resources.ArrayBuilder_Text_LogicalDrive_RemainingSpace, logicalDriveNumber);
                }
                else if (string.Compare(logicalDriveSize, REMAINING_SPACE, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    nodeTitle = string.Format(Properties.Resources.ArrayBuilder_Text_LogicalDrive_RemainingSpace, logicalDriveNumber);
                }
                else if (string.Compare(logicalDriveType, PERCENT_SIZE, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    nodeTitle = string.Format(Properties.Resources.ArrayBuilder_Text_LogicalDrive_Percent, logicalDriveNumber, logicalDriveSize);
                }
                else
                {
                    int size = 0;
                    if (int.TryParse(logicalDriveSize, out size))
                    {
                        logicalDriveSize = size.ToString("n0");
                    }
                    nodeTitle = string.Format(Properties.Resources.ArrayBuilder_Text_LogicalDrive_GigabyteShort, logicalDriveNumber, logicalDriveSize);
                }
            }
            else
            {
                nodeTitle = Properties.Resources.ArrayBuilder_Text_LogicalDrive + " " + logicalDriveNumber +
                    " (" + Properties.Resources.ArrayBuilder_Text_Unknown + ")";
            }
            return nodeTitle;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="diskNode"></param>
        /// <returns></returns>
        internal static string SetDiskNodeTitle(XmlNode diskNode)
        {
            if (diskNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "diskNode");
            }
            string parentType = null;
            XmlNode diskParent = diskNode.ParentNode.ParentNode;
            if (diskParent != null)
            {
                parentType = diskParent.Name.ToString();
            }
            string diskNum = IntegrationKitUtilities.GetXmlAttribute(diskNode, "Number");
            string diskUse = IntegrationKitUtilities.GetXmlAttribute(diskNode, "Usage");
            string nodeTitle = string.Empty;

            if (string.IsNullOrEmpty(diskNum) == false)
            {
                if (diskNum.StartsWith(Utilities.ALL_REMAINING, StringComparison.OrdinalIgnoreCase))
                {
                    nodeTitle = Properties.Resources.ArrayBuilder_Text_AllRemainingDisks;
                }
                else
                {
                    nodeTitle = Properties.Resources.ArrayBuilder_Text_Disk + " " + diskNum;
                }
            }
            if (string.IsNullOrEmpty(diskUse) == false)
            {
                if ((GetNodeType(diskParent) == NodeType.Array) ||
                    (GetNodeType(diskParent) == NodeType.JbodArray))
                {
                    if (string.Compare(diskUse, HOT_SPARE_DISK, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        diskUse = Properties.Resources.ArrayBuilder_Text_HotSpare;
                        nodeTitle = nodeTitle + " - " + diskUse;
                    }
                }
                else if (GetNodeType(diskParent) == NodeType.GlobalHotSpares)
                {
                    diskUse = Properties.Resources.ArrayBuilder_Text_GlobalHotSpare;
                    nodeTitle = nodeTitle + " - " + diskUse;
                }
            }
            return nodeTitle;
        }

        
        //===================[ Node Search Methods ]=============================
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static NodeType GetNodeType(TreeNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }
            if (node.Tag == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node.Tag");
            }

            Type nodeTagType = node.Tag.GetType();

            if (string.Compare(nodeTagType.Name, "NodeType", StringComparison.OrdinalIgnoreCase) == 0)
            {
                return (NodeType)node.Tag;
            }
            return NodeType.None;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static NodeType GetNodeType(XmlNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }

            // all of these conditions cover nodes which are in the tree and also have XML nodes
            //  the Physical Disks node and Logical Drives node do not have XML nodes

            if (string.Compare(node.Name, XMLNODE_CONTROLLER, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return NodeType.Controller;
            }
            else if (string.Compare(node.Name, XMLNODE_VARIABLE, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return NodeType.Variable;
            }
            else if (string.Compare(node.Name, XMLNODE_ARRAY, StringComparison.OrdinalIgnoreCase) == 0)
            {
                string arrayType = IntegrationKitUtilities.GetXmlAttribute(node, "RaidLevel");
                if ((string.IsNullOrEmpty(arrayType) == false) &&
                    (string.Compare(arrayType, ARRAY_NO_RAID, StringComparison.OrdinalIgnoreCase) == 0))
                {
                    return NodeType.JbodArray;
                }
                else
                {
                    return NodeType.Array;
                }
            }
            else if (string.Compare(node.Name, XMLNODE_GLOBALHOTSPARES, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return NodeType.GlobalHotSpares;
            }
            else if (string.Compare(node.Name, XMLNODE_LOGICALDRIVE, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return NodeType.LogicalDrive;
            }
            else if (string.Compare(node.Name, XMLNODE_DISK, StringComparison.OrdinalIgnoreCase) == 0)
            {
                if (GetNodeType(node.ParentNode.ParentNode) == NodeType.GlobalHotSpares)
                {
                    return NodeType.GlobalHotSpare;
                }
                else if (GetNodeType(node.ParentNode.ParentNode) == NodeType.JbodArray)
                {
                    return NodeType.JbodDisk;
                }
                else if (GetNodeType(node.ParentNode.ParentNode) == NodeType.Array)
                {
                    string diskType = IntegrationKitUtilities.GetXmlAttribute(node, "Usage");
                    string diskNumber = IntegrationKitUtilities.GetXmlAttribute(node, "Number");
                    if ((string.IsNullOrEmpty(diskType) == false) &&
                        (string.Compare(diskType, HOT_SPARE_DISK, StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        return NodeType.HotSpare;
                    }
                    if ((string.IsNullOrEmpty(diskNumber) == false) &&
                        (string.Compare(diskNumber, ALL_REMAINING, StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        return NodeType.AllRemainingDisks;
                    }
                    return NodeType.Disk;
                }
                else
                {
                    return NodeType.Disk;
                }
            }
            else if (string.Compare(node.Name, XMLNODE_DISKS, StringComparison.OrdinalIgnoreCase) == 0)
            {
                if (GetNodeType(node.ParentNode) == NodeType.GlobalHotSpares)
                {
                    return NodeType.GlobalHotSpares;
                }
                else
                {
                    return NodeType.PhysicalDisks;
                }
            }

            // should have returned a value before this point. If not, that's an error so throw an exception

            //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            return NodeType.None;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="variableNode"></param>
        /// <returns></returns>
        internal static XmlNode GetNonRaidArrayNode(XmlNode variableNode)
        {
            if (variableNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "variableNode");
            }

            XmlNodeList arrayNodes = IntegrationKitUtilities.GetXmlNodeList(variableNode, XPATH_ARRAY_NODELIST);
            if ((arrayNodes != null) && (arrayNodes.Count > 0))
            {
                foreach (XmlNode arrayNode in arrayNodes)
                {
                    if (string.Compare(IntegrationKitUtilities.GetXmlAttribute(arrayNode, "RaidLevel"),
                        ARRAY_NO_RAID, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return arrayNode;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static XmlNode GetFirstLogicalDriveInArray(XmlNode arrayNode)
        {
            if (arrayNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayNode");
            }
            XmlNode logicalDriveNode = IntegrationKitUtilities.GetXmlNode(arrayNode, XPATH_LOGICAL_DRIVE_NODELIST);
            if (logicalDriveNode == null)
            {
                //no logical drives exist
                return null;
            }
            else
            {
                return logicalDriveNode;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static XmlNode GetAllRemainingDisksNodeInArray(XmlNode arrayNode)
        {
            if (arrayNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayNode");
            }
            XmlNode allRemainingDisk = IntegrationKitUtilities.GetXmlNode(arrayNode, XPATH_ALL_REMAINING_DISK_NODE);
            if (allRemainingDisk == null)
            {
                //the "all remaining disks" node does not exist
                return null;
            }
            else
            {
                return allRemainingDisk;
            }
        }
               
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static XmlNode GetMaximumSizeLogicalDriveInArray(XmlNode arrayNode)
        {
            if (arrayNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayNode");
            }
            XmlNode logicalDrive = IntegrationKitUtilities.GetXmlNode(arrayNode, XPATH_LOGICAL_DRIVE_DEFAULT_NODE);

            if (logicalDrive == null)
            {
                //the "max size" logical drive does not exist
                return null;
            }
            else
            {
                return logicalDrive;
            }
        }


        //===================[ Supported Options]===============================

        /// <summary>
        ///     
        /// </summary>
        /// <param name="configInfo" type="System.Xml.XmlDocument">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        internal static bool IsLogicalDrivePercentSupported(XmlDocument configInfo)
        {
            XmlNode supportedOptions = IntegrationKitUtilities.GetXmlNode(configInfo, XPATH_ARRAYBUILDER_SUPPORTEDOPTION_LOGICALDRIVEPERCENT);
            if (supportedOptions != null)
            {
                if (string.Compare("false", IntegrationKitUtilities.GetXmlAttribute(supportedOptions, "Enabled"), StringComparison.OrdinalIgnoreCase) == 0)
                {
                     //the option is disabled
                    return false;
                }
            }
            return true;

        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="configInfo" type="System.Xml.XmlDocument">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A int? value...
        /// </returns>
        internal static int? MaxGlobalHotSparesSupported(XmlDocument configInfo)
        {
            XmlNode supportedOptions = IntegrationKitUtilities.GetXmlNode(configInfo, XPATH_ARRAYBUILDER_SUPPORTEDOPTION_MAXGHSDISKS);
            if (supportedOptions != null)
            {
                string qtyAllowed = IntegrationKitUtilities.GetXmlAttribute(supportedOptions, "Qty");
                int qty;
                if (int.TryParse(qtyAllowed, out qty))
                {
                    return (int?)qty;
                }
            }
            return null;

        }
        
        /// <summary>
        ///     
        /// </summary>
        /// <param name="configInfo" type="System.Xml.XmlDocument">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A int? value...
        /// </returns>
        internal static int? MaxHotSparesSupportedPerArray(XmlDocument configInfo)
        {
            XmlNode supportedOptions = IntegrationKitUtilities.GetXmlNode(configInfo, XPATH_ARRAYBUILDER_SUPPORTEDOPTION_MAXHOTSPAREDISKS);
            if (supportedOptions != null)
            {
                string qtyAllowed = IntegrationKitUtilities.GetXmlAttribute(supportedOptions, "Qty");
                int qty;
                if (int.TryParse(qtyAllowed, out qty))
                {
                    return (int?)qty;
                }
            }
            return null;

        }

        /// <summary>
        /// Used when a controller specifies an exact disk quantity. 
        /// Converts "All Remaining Disks" nodes into standard disk nodes.
        /// </summary>
        /// <param name="controllerNode">An XmlNode representing the controller</param>
        /// <returns>The modified XmlNode for the controller</returns>
        internal static XmlNode ConvertAllRemainingDiskNodesOnController(XmlNode controllerNode)
        {
            ArgumentNotNull(controllerNode, "controllerNode");

            //if the controller does not require an exact number of disks, just return
            if (Utilities.IsControllerFixedDiskQty(controllerNode) == false)
            {
                return controllerNode;
            }

            XmlNodeList variableNodes = IntegrationKitUtilities.GetXmlNodeList(controllerNode, Utilities.XPATH_VARIABLE_NODELIST);
            ArgumentNotNull(variableNodes, "variableNodes");
            ArgumentNodeListCountGreaterThanZero(variableNodes, "variableNodes");

            // Loop through all of the variable nodes
            for (int i = 0; i < variableNodes.Count; i++)
            {
                XmlNode allDiskNode = IntegrationKitUtilities.GetXmlNode(variableNodes[i], Utilities.XPATH_ALL_REMAINING_DISK_NODE);
                if (allDiskNode != null)
                {
                    allDiskNode.Attributes.RemoveAll();
                    XmlAttribute diskNumber = allDiskNode.OwnerDocument.CreateAttribute("Number");
                    XmlAttribute diskUsage = allDiskNode.OwnerDocument.CreateAttribute("Usage");
                    diskNumber.Value = "1";
                    diskUsage.Value = Utilities.STANDARD_DISK;
                    allDiskNode.Attributes.Append(diskNumber);
                    allDiskNode.Attributes.Append(diskUsage);

                }
            }
            return controllerNode;
        }


        


        #region "Get Quantity" Methods

        /// <summary>
        /// Determines if the controller specifies a minimum number of disks, and if so, returns that value.
        /// </summary>
        /// <param name="controllerNode">An XmlNode containing the controller to be queried.</param>
        /// <returns>An integer value representing the minimum number of disks required on the controller. Returns -1 on error or 0 when thee is no disk requirement.</returns>
        internal static int GetControllerMinimumDiskQty(XmlNode controllerNode)
        {
            // check the parameter passed in
            ArgumentNotNull(controllerNode, "controllerNode");

            int minDrives = 0;
            //if the 'ControllerMatch' attribute is set to 'Any', then it refers to a number of disks
            if (string.Compare(
                IntegrationKitUtilities.GetXmlAttribute(controllerNode, "ControllerMatch"),
                CONTROLLER_MATCH_ANY, 
                StringComparison.OrdinalIgnoreCase) == 0)
            {
                // parse the string value to an int. If parsing fails, return 0, otherwise return the quantity
                if (int.TryParse(IntegrationKitUtilities.GetXmlAttribute(controllerNode, "NumberOfDisks"), out minDrives) == false)
                {
                    return 0;
                }
            }
            return minDrives;
        }

        /// <summary>
        /// Gets the total number of disks assigned to this variable condition, located in all arrays.
        /// </summary>
        /// <param name="variableNode">An XmlNode representing the variable condition</param>
        /// <returns>An integer value of the number of disks (will always be greater than 0)</returns>
        internal static int GetVariableDiskQty(XmlNode variableNode)
        {
            XmlNodeList disks = IntegrationKitUtilities.GetXmlNodeList(variableNode, XPATH_DISK_NODELIST);
            if ((disks == null) || (disks.Count == 0))
            {
                // Modified 6/2/09 by rhearn to fix issue 4395, incorrectly throwing an exception when value should be zero
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "disks");
                return 0;
            }
            return disks.Count;
        }

        /// <summary>
        /// Gets the quantity of disks assigned to the non-RAID disks node.
        /// </summary>
        /// <param name="variableNode">An XmlNode representing the variable condition where you want to find the disks.</param>
        /// <returns>An integer of the disk quantity (0 or greater)</returns>
        internal static int GetJbodDiskQty(XmlNode variableNode)
        {
            ArgumentNotNull(variableNode, "variableNode");
            //int DiskQuantity = 0;

            XmlNodeList diskNodes = IntegrationKitUtilities.GetXmlNodeList(variableNode, XPATH_NON_RAID_ARRAY_DISKS_NODELIST);
            if ((diskNodes != null) && (diskNodes.Count != 0))
            {
                return diskNodes.Count;
            }
            return 0;
        }

        /// <summary>
        /// Gets the quantity of hot spare disks assigned to an array node.
        /// </summary>
        /// <param name="arrayNode">An XmlNode representing the array where you want to find the disks.</param>
        /// <returns>An integer of the disk quantity (0 or greater)</returns>
        internal static int GetArrayHotSpareDiskQty(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            //int DiskQuantity = 0;

            XmlNodeList diskNodes = IntegrationKitUtilities.GetXmlNodeList(arrayNode, XPATH_ARRAY_HOT_SPARE_DISKS_NODELIST);
            if ((diskNodes != null) && (diskNodes.Count != 0))
            {
                return diskNodes.Count;
            }
            return 0;
        }

        /// <summary>
        /// Gets the quantity of disks assigned to the Global Hot Spares node.
        /// </summary>
        /// <param name="variableNode">An XmlNode representing the variable condition where you want to find the disks.</param>
        /// <returns>An integer of the disk quantity (0 or greater)</returns>
        internal static int GetGlobalHotSpareDiskQty(XmlNode variableNode)
        {
            ArgumentNotNull(variableNode, "variableNode");
            //int DiskQuantity = 0;

            XmlNodeList diskNodes = IntegrationKitUtilities.GetXmlNodeList(variableNode, XPATH_GLOBAL_HOT_SPARE_DISKS_NODELIST);
            if ((diskNodes != null) && (diskNodes.Count != 0))
            {
                return diskNodes.Count;
            }
            return 0;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static int GetArrayLogicalDriveQty(XmlNode arrayNode)
        {
            if (arrayNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayNode");
            }

            XmlNodeList logicalDriveNodes = IntegrationKitUtilities.GetXmlNodeList(arrayNode, XPATH_LOGICAL_DRIVE_NODELIST);
            if ((logicalDriveNodes == null) || (logicalDriveNodes.Count == 0))
            {
                return 0;
            }
            else
            {
                return logicalDriveNodes.Count;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static int GetArrayTotalDiskQty(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");

            XmlNodeList diskNodes = IntegrationKitUtilities.GetXmlNodeList(arrayNode, XPATH_DISK_NODELIST);
            if ((diskNodes == null) || (diskNodes.Count == 0))
            {
                return 0;
            }
            else
            {
                return diskNodes.Count;
            }
        }

        /// <summary>
        /// Gets the number of disks in an array that are not set as hot spare disks. This is the number
        /// of disks that are currently counted or available for a RAID array.
        /// </summary>
        /// <param name="arrayNode">An XmlNode representing the array to check</param>
        /// <returns>An integer value with the number of disks (0 or higher)</returns>
        internal static int GetArrayRaidDiskQty(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            
            XmlNode arrayDisksNode = IntegrationKitUtilities.GetXmlNode(arrayNode, XPATH_DISKS_NODE);
            ArgumentNotNull(arrayDisksNode, "arrayDisksNode"); 

            int numDrives = 0;
            // If there is an "All remaining" node, the RAID will always be valid even if no other disks
            // If a drive is a Hot Spare, it doesn't count in the RAID number

            foreach (XmlNode driveNode in arrayDisksNode.ChildNodes)
            {
                if (GetNodeType(driveNode) == NodeType.HotSpare)
                {
                    //do nothing - don't count this drive;
                }
                else if (Utilities.IsAllRemainingDisksInArray(arrayNode))
                {
                    numDrives++;
                }
                else
                {
                    numDrives++;
                }
            }
            return numDrives;
        }

        /// <summary>
        /// A lookup function that returns a quantity of disks required to meet a specific RAID level.
        /// </summary>
        /// <param name="arrayType">A string representing the RAID level (a number)</param>
        /// <returns>An integer value with the minimum number of disks required for the RAID level</returns>
        internal static int GetRaidMinimumDiskQty(string arrayType)
        {
            ArgumentNotNullOrEmpty(arrayType, "arrayType");

            switch (arrayType.ToUpperInvariant())
            {
                case "0":
                    return MIN_DRIVES_RAID_0;

                case "1":
                    return MIN_DRIVES_RAID_1;

                case "5":
                    return MIN_DRIVES_RAID_5;

                case "6":
                    return MIN_DRIVES_RAID_6;

                case "10":
                    return MIN_DRIVES_RAID_10;

                case "50":
                    return MIN_DRIVES_RAID_50;

                case "60":
                    return MIN_DRIVES_RAID_60;

                case ARRAY_DYNAMIC:
                    return MIN_DRIVES_RAID_DYNAMIC;

                case ARRAY_NO_RAID:
                    return MIN_DRIVES_RAID_NONE;

                default:
                    return MIN_DRIVES_RAID_NONE;
            }
        }

        /// <summary>
        /// A lookup function that returns a quantity of disks required to meet a specific RAID level.
        /// </summary>
        /// <param name="arrayNode">An XmlNode value representing the array to use for determining the level</param>
        /// <returns>An integer value with the minimum number of disks required for the RAID level</returns>
        internal static int GetRaidMinimumDiskQty(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            
            string arrayType = IntegrationKitUtilities.GetXmlAttribute(arrayNode, "RaidLevel");
            ArgumentNotNullOrEmpty(arrayType, "arrayType");

            return GetRaidMinimumDiskQty(arrayType);
        }


        #endregion

        #region Boolean Methods



        //===================[ Controllers ]=============================


        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static bool IsAllRemainingControllersNode(TreeNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }
            if ((node != null) &&
                (Utilities.GetNodeType(node) == NodeType.Controller) && 
                (node.Text.Contains(Properties.Resources.ArrayBuilder_Text_AllRemainingControllers)))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Determines if the controller requires an exact number of disks (instead of "at least" a number of disks or has no requirement).
        /// </summary>
        /// <param name="controllerNode">An XmlNode containing the controller to be queried.</param>
        /// <returns>A boolean value indicating whether an exact number of disks is required.</returns>
        internal static bool IsControllerFixedDiskQty(XmlNode controllerNode)
        {
            if (controllerNode == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "controllerNode");
            }

            if ((controllerNode != null) &&
                (string.Compare(IntegrationKitUtilities.GetXmlAttribute(controllerNode, "ControllerMatch"), CONTROLLER_MATCH_ANY, StringComparison.OrdinalIgnoreCase) == 0) &&
                (string.Compare(IntegrationKitUtilities.GetXmlAttribute(controllerNode, "DiskMatch"), DRIVE_MATCH_TYPE_EQUAL, StringComparison.OrdinalIgnoreCase) == 0))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Determines if an "All Remaining Controllers" node exists, and if so, returns true. Otherwise, returns false.
        /// </summary>
        /// <returns>Boolean value representing whether or not an "All Remaining Controllers" node exists.</returns>
        internal static bool IsAllRemainingControllersInRule(XmlNode node)
        {
            ArgumentNotNull(node, "node");

            XmlNode controllerNode = IntegrationKitUtilities.GetXmlNode(node, XPATH_ALL_REMAINING_CONTROLLER_NODE);
            if (controllerNode != null)
            {
                return true;
            }
            return false;
        }



        //===================[ Variables ]=============================

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static bool IsDefaultVariableNode(TreeNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }

            if ((node != null) &&
                ((NodeType)node.Tag == NodeType.Variable) &&
                (string.Compare(node.Text, Properties.Resources.ArrayBuilder_Text_WhereVariableNotSet, StringComparison.OrdinalIgnoreCase) == 0))
            {
                return true;
            }
            
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="controllerNode"></param>
        /// <returns></returns>
        internal static bool DefaultVariableConditionExists(XmlNode controllerNode)
        {
            ArgumentNotNull(controllerNode, "controllerNode");

            XmlNodeList variableNodes = IntegrationKitUtilities.GetXmlNodeList(controllerNode, XPATH_VARIABLE_NODELIST);
            if ((variableNodes != null) && (variableNodes.Count > 0))
            {
                for (int i = 0; i < variableNodes.Count; i++)
                {
                    string attrib = IntegrationKitUtilities.GetXmlAttribute(variableNodes[i], "VariableName");
                    if (string.IsNullOrEmpty(attrib))
                    {
                        //found a default variable. exit here so another one is not added.
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="variableNode"></param>
        /// <returns></returns>
        internal static bool IsAllRemainingDisksInVariableCondition(XmlNode variableNode)
        {
            ArgumentNotNull(variableNode, "variableNode");

            XmlNode diskNode = IntegrationKitUtilities.GetXmlNode(variableNode, XPATH_ALL_REMAINING_DISK_NODE);
            if (diskNode != null)
            {
                return true;
            }
            return false;
        }



        //===================[ Arrays ]=============================

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <param name="diskNode"></param>
        /// <returns></returns>
        internal static bool IsArrayValidAfterDeletingDisk(XmlNode arrayNode, XmlNode diskNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            ArgumentNotNull(diskNode, "diskNode");

            // Find out how many disks are present, and if this one is removed, will the RAID still be valid.
            // Otherwise, if the number of disks is > the minimum needed for the raid, it's ok
            NodeType nType = GetNodeType(diskNode);
            
            if ((GetNodeType(arrayNode) == NodeType.JbodArray) ||
                (GetNodeType(arrayNode) == NodeType.GlobalHotSpares))
            {
                //non-RAID disk sets & Global Hot Spares nodes aren't counted
                return true;
            }
            if ((nType == NodeType.HotSpare) ||
                (nType == NodeType.GlobalHotSpare))
            {
                //hot spares aren't counted in array numbers, so it can be deleted freely.
                return true;
            }
            
            // Evaluate the RAID level and if the RAID has enough disks after removing this one.
            string arrayType = IntegrationKitUtilities.GetXmlAttribute(arrayNode, "RaidLevel");
            ArgumentNotNullOrEmpty(arrayType, "arrayType");

            int numDisks = GetArrayRaidDiskQty(arrayNode);
            int numDisksRequired = GetRaidMinimumDiskQty(arrayType);

            // if current number > than the number required, then we can delete one
            if (numDisks > numDisksRequired)
            {
                //however, if the RAID requires an even number of disks, see if we can delete two disks
                if ((RaidRequiresEvenDiskQty(arrayType) == true) && ((numDisks % 2) == 0))
                {
                    //This RAID level requires an even number of disks, 
                    //so check to see if removing 2 disks will make it invalid
                    if (numDisks - 2 < numDisksRequired)
                    {
                        return false;
                    }
                }
                return true;
            }
            
            // If the current number of disks is not greater than the RAID requirements, we can't delete a disk
            return false;
        }

        /// <summary>
        /// Determines if the RAID level provided requires an even number of disks.
        /// </summary>
        /// <param name="arrayType">A string value indicating the RAID level</param>
        /// <returns>True if the RAID requires an even number of disks, otherwise false</returns>
        internal static bool RaidRequiresEvenDiskQty(string arrayType)
        {
            ArgumentNotNullOrEmpty(arrayType, "arrayType");
            if ((string.Compare(arrayType, "1", StringComparison.OrdinalIgnoreCase) == 0) ||
                (string.Compare(arrayType, "10", StringComparison.OrdinalIgnoreCase) == 0))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Determines if the RAID level of the given array (XmlNode) requires an even number of disks.
        /// </summary>
        /// <param name="arrayNode">An XmlNode representing the array in question</param>
        /// <returns>True if the RAID requires an even number of disks, otherwise false</returns>
        internal static bool RaidRequiresEvenDiskQty(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            if ((GetNodeType(arrayNode) == NodeType.JbodArray) ||
                (GetNodeType(arrayNode) == NodeType.GlobalHotSpares))
            {
                return false;
            }
            string arrayType = IntegrationKitUtilities.GetXmlAttribute(arrayNode, "RaidLevel");
            ArgumentNotNullOrEmpty(arrayType, "arrayType");

            return RaidRequiresEvenDiskQty(arrayType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static bool IsRaidValid(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            if ((GetNodeType(arrayNode) == NodeType.JbodArray) ||
                (GetNodeType(arrayNode) == NodeType.GlobalHotSpares))
            {
                return true;
            }

            if (IsAllRemainingDisksInArray(arrayNode))
            {
                return true;
            }

            string arrayType = IntegrationKitUtilities.GetXmlAttribute(arrayNode, "RaidLevel");
            ArgumentNotNullOrEmpty(arrayType, "arrayType");

            int numDrives = GetArrayRaidDiskQty(arrayNode);
            ArgumentNotNegative(numDrives, "numDrives");

            if (numDrives >= GetRaidMinimumDiskQty(arrayType))
            {
                if ((RaidRequiresEvenDiskQty(arrayType)) &&
                   ((numDrives % 2) != 0))
                {
                    return false;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static bool IsAllRemainingDisksInArray(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");
            XmlNode allRemainingDisk = IntegrationKitUtilities.GetXmlNode(arrayNode, XPATH_ALL_REMAINING_DISK_NODE);
            if (allRemainingDisk == null)
            {
                //the "all remaining disks" node does not exist
                return false;
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="arrayNode"></param>
        /// <returns></returns>
        internal static bool IsLastArrayInVariable(XmlNode arrayNode)
        {
            ArgumentNotNull(arrayNode, "arrayNode");

            //if the next node is the non-RAID node (test this first) or there is no next node, this is the last array
            if (((arrayNode.NextSibling != null) && (IntegrationKitUtilities.GetXmlAttribute(arrayNode.NextSibling, "RaidLevel") == ARRAY_NO_RAID))
                ||
                (arrayNode.NextSibling == null))
            {
                return true;
            }
            return false;
        }

        //===================[ Logical Drives ]=============================
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static bool IsDefaultLogicalDriveNode(TreeNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }

            if ((node != null) &&
                (GetNodeType(node) == NodeType.LogicalDrive) && 
                (node.Text.Contains(Properties.Resources.ArrayBuilder_Text_LogicalDrive_Maximum)))
            {
                return true;
            }
            
            return false;
        }


        //===================[ Disks ]=============================
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static bool IsAllRemainingDisksNode(TreeNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }
            if ((node != null) && 
                (string.Compare(node.Text, Properties.Resources.ArrayBuilder_Text_AllRemainingDisks, StringComparison.OrdinalIgnoreCase) == 0))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static bool IsAllRemainingDisksNode(XmlNode node)
        {
            if (node == null)
            {
                //throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "node");
            }
            else
            {
                string diskUse = IntegrationKitUtilities.GetXmlAttribute(node, "Number");
                if (string.Compare(diskUse, ALL_REMAINING, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return true;
                }
            }
            return false;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal static bool IsPhysicalDisk(TreeNode node)
        {
            ArgumentNotNull(node, "node");

            if (((NodeType)node.Tag == NodeType.Disk) ||
                ((NodeType)node.Tag == NodeType.JbodDisk) ||
                ((NodeType)node.Tag == NodeType.HotSpare) ||
                ((NodeType)node.Tag == NodeType.AllRemainingDisks) ||
                ((NodeType)node.Tag == NodeType.GlobalHotSpare))
            {
                return true;
            }
            return false;
        }

        //internal static bool IsNodeValidForAddingDisks(TreeNode tNode)
        //{
        //    if (tNode == null)
        //    {
        //        return false;
        //    }

        //    if (((NodeType)tNode.Tag == NodeType.Controller) ||
        //        ((NodeType)tNode.Tag == NodeType.Variable) ||
        //        ((NodeType)tNode.Tag == NodeType.LogicalDrive) ||
        //        ((NodeType)tNode.Tag == NodeType.LogicalDrives))
        //    {
        //        return false;
        //    }
        //    else
        //    {
        //        return true;
        //    }
        //}

        
        //internal static bool IsEnoughDisksToCreateArray(XmlNode variableNode, XmlNode arrayNode, string arrayType)
        //{
        //    if (variableNode == null)
        //    {
        //        throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "variableNode");
        //    }
        //    if (string.IsNullOrEmpty(arrayType))
        //    {
        //        throw new System.ArgumentException(Properties.Resources.ArrayBuilder_Error_InvalidParameter, "arrayType");
        //    }
        //    try
        //    {
        //        XmlNode controllerNode = variableNode.ParentNode.ParentNode;

        //        if (IsControllerFixedDiskQty(controllerNode) == false)
        //        {
        //            // no disk requirement on controller, so no problem
        //            return true;
        //        }
        //        int numCurrentArrayDisks = 0;
        //        if (arrayNode != null)
        //        {
        //            XmlNodeList arrayDisks = IntegrationKitUtilities.GetXmlNodeList(arrayNode, XPATH_DISK_NODELIST);
        //            numCurrentArrayDisks = arrayDisks.Count;
        //        }
        //        int numDisksRequired = GetControllerMinimumDiskQty(controllerNode);
        //        int numDisksForRaid = GetRaidMinimumDiskQty(arrayType);

        //        XmlNodeList nonRaidDisks = IntegrationKitUtilities.GetXmlNodeList(variableNode, XPATH_NON_RAID_ARRAY_DISKS_NODELIST);
        //        int numNonRaidDisks = nonRaidDisks.Count + numCurrentArrayDisks;

        //        if (numNonRaidDisks < numDisksForRaid)
        //        {
        //            return false;
        //        }
        //        return true;
        //    }
        //    catch
        //    {
        //        //ShowNotificationMessage("An exception occurred when trying to find the number of disks available for this array");
        //        return false;
        //    }
        //}
        
        //internal static bool IsControllerValidAfterDeletingDisk(XmlNode controllerNode, XmlNode diskNode)
        //{
        //    if (controllerNode == null)
        //    {
        //        throw new System.ArgumentNullException("controllerNode", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
        //    }
        //    if (diskNode == null)
        //    {
        //        throw new System.ArgumentNullException("diskNode", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
        //    }

        //    // Find out how many disks are present, and if this one is removed, will the controller still be valid.
        //    // Otherwise, if the number of disks is > the minimum needed for the controller, it's ok
        //    XmlNodeList disks = IntegrationKitUtilities.GetXmlNodeList(controllerNode, ".//Disk");
        //    int numDisks = disks.Count;

        //    int numDisksRequired = GetControllerMinimumDiskQty(controllerNode);

        //    if (numDisks > numDisksRequired)
        //    {
        //        return true;
        //    }
        //    return false;
        //}

        
        #endregion


        #region Validation

        public static void ArgumentNotNull(object value, string parameterName)
        {
            if (value == null)
                throw new ArgumentNullException(parameterName);
        }

        public static void ArgumentNotNullOrEmpty(string value, string parameterName)
        {
            if (value == null)
                throw new ArgumentNullException(parameterName);

            if (string.IsNullOrEmpty(value))
                throw new ArgumentException(string.Format("'{0}' cannot be empty.", parameterName), parameterName);
        }

        public static void ArgumentGreaterThanZero(int value, string parameterName)
        {
            if (value < 1)
                throw new ArgumentException(string.Format("'{0}' must be greater than 0.", parameterName), parameterName);
        }

        public static void ArgumentNotNegative(int value, string parameterName)
        {
            if (value < 0)
                throw new ArgumentException(string.Format("'{0}' must be greater than or equal to zero.", parameterName), parameterName);
        }

        public static void ArgumentNodeListCountGreaterThanZero(XmlNodeList value, string parameterName)
        {
            if (value == null)
                throw new ArgumentNullException(parameterName);

            if (value.Count < 1)
                throw new ArgumentException(string.Format("'{0}' count must be greater than 0.", parameterName), parameterName);
        }

        #endregion



    }

    #region Not used


    // /// <summary>
    ///// 
    ///// </summary>
    ///// <param name="ex"></param>
    ///// <returns></returns>
    //internal static bool IsCritical(Exception ex)
    //{
    //    if (ex is OutOfMemoryException) return true;
    //    if (ex is AppDomainUnloadedException) return true;
    //    if (ex is BadImageFormatException) return true;
    //    if (ex is CannotUnloadAppDomainException) return true;
    //    if (ex is ExecutionEngineException) return true;
    //    if (ex is InvalidProgramException) return true;
    //    if (ex is System.Threading.ThreadAbortException)
    //        return true;
    //    return false;
    //}


     //internal static XmlNode GetTopXmlNodeFromTree(XmlDocument XmlContent, TreeNode treeNode)
     //   {
     //       if (treeNode == null)
     //       {
     //           //throw new System.ArgumentException("treeNode", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }
     //       XmlNodeList controllersList = IntegrationKitUtilities.GetXmlNodeList(XmlContent, "//Controller");
     //       if (controllersList == null)
     //       {
     //           //throw new System.ArgumentException("controllersList", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }
     //       XmlNode xNode = null;
     //       if ((NodeType)treeNode.Tag == NodeType.Controller)
     //       {
     //           xNode = controllersList[treeNode.Index];
     //       }
     //       else if ((NodeType)treeNode.Tag == NodeType.Variable)
     //       {
     //           if (treeNode.Parent == null)
     //           {
     //               //throw new System.ArgumentException("treeNode.Parent", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //           }
     //           xNode = controllersList[treeNode.Parent.Index];
     //       }
     //       else if (((NodeType)treeNode.Tag == NodeType.Array) ||
     //           ((NodeType)treeNode.Tag == NodeType.JbodArray) ||
     //           ((NodeType)treeNode.Tag == NodeType.GlobalHotSpares))
     //       {
     //           if (treeNode.Parent.Parent == null)
     //           {
     //               //throw new System.ArgumentException("treeNode.Parent.Parent", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //           }
     //           xNode = controllersList[treeNode.Parent.Parent.Index];
     //       }
     //       else if (((NodeType)treeNode.Tag == NodeType.PhysicalDisks) ||
     //           ((NodeType)treeNode.Tag == NodeType.LogicalDrives) ||
     //           ((NodeType)treeNode.Tag == NodeType.GlobalHotSpare))
     //       {
     //           if (treeNode.Parent.Parent.Parent == null)
     //           {
     //               //throw new System.ArgumentException("treeNode.Parent.Parent.Parent", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //           }
     //           xNode = controllersList[treeNode.Parent.Parent.Parent.Index];
     //       }
     //       else if (((NodeType)treeNode.Tag == NodeType.Disk) || ((NodeType)treeNode.Tag == NodeType.LogicalDrive))
     //       {
     //           if (treeNode.Parent.Parent.Parent.Parent == null)
     //           {
     //               //throw new System.ArgumentException("treeNode.Parent.Parent.Parent.Parent", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //           }
     //           xNode = controllersList[treeNode.Parent.Parent.Parent.Parent.Index];
     //       }
     //       else
     //       {
     //           //throw new System.ArgumentException("treeNode.Tag", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }
     //       return xNode;
     //   }

     //   internal static XmlNode GetXmlNodeFromTreeNode(TreeNode treeNode, Dictionary<TreeNode, XmlNode> treeNodeToXml)
     //   {
     //       if (treeNode == null)
     //       {
     //           throw new System.ArgumentNullException("treeNode", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }
     //       if (treeNodeToXml == null)
     //       {
     //           throw new System.ArgumentNullException("treeNodeToXml", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }

     //       XmlNode xNode = null;
     //       if (treeNodeToXml.TryGetValue(treeNode, out xNode) == false)
     //       {
     //           return null;
     //       }
     //       return xNode;

     //   }

     //   internal static TreeNode GetTreeNodeFromXmlNode(XmlNode xNode, Dictionary<XmlNode, TreeNode> xmlToTreeNode)
     //   {
     //       if (xNode == null)
     //       {
     //           throw new System.ArgumentNullException("xNode", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }
     //       if (xmlToTreeNode == null)
     //       {
     //           throw new System.ArgumentNullException("xmlToTreeNode", Properties.Resources.ArrayBuilder_Error_InvalidParameter);
     //       }

     //       TreeNode tNode = null;
     //       if (xmlToTreeNode.TryGetValue(xNode, out tNode) == false)
     //       {
     //           return null;
     //       }
     //       return tNode;

     //   }
        





   

    //internal class ThreadExceptionHandler
    //{
    //    /// 
    //    /// Handles the thread exception.
    //    /// 
    //    internal void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    //    {
    //        try
    //        {
    //            // Exit the program if the user clicks Abort.
    //            DialogResult result = ShowThreadExceptionDialog(
    //                e.Exception);

    //            if (result == DialogResult.Abort)
    //                Application.Exit();
    //        }
    //        catch
    //        {
    //            // Fatal error, terminate program
    //            try
    //            {
    //                MessageBox.Show("Fatal Error",
    //                    "Fatal Error",
    //                    MessageBoxButtons.OK,
    //                    MessageBoxIcon.Stop);
    //            }
    //            finally
    //            {
    //                Application.Exit();
    //            }
    //        }
    //    }
    //} 
    
    
    
    #endregion
}
